<template>
  <div class="filter-selected-value">
    <div class="header">
      <span
        v-for="tab in tabData"
        :key="tab.key"
        :class="{ tabs: true, active: activeKey === tab.key }"
        @click="toggleTabKey(tab)"
      >
        {{ tab.name }}
      </span>
    </div>
    <a-input
      v-show="['varchar', 'text'].includes(column.desc)"
      v-model="inputValue"
      size="small"
      class="search-box"
      @pressEnter="searchOptions"
    />
    <a-popover
      v-show="['varchar', 'text'].includes(column.desc)"
      title="搜索选项"
      trigger="click"
    >
      <template slot="content">
        <a-radio-group v-model="filterType" @change="onFilterTypeChange">
          <a-radio :style="radioStyle" value="like">包含</a-radio>
          <a-radio :style="radioStyle" value="start">开始为</a-radio>
          <a-radio :style="radioStyle" value="=">精确匹配</a-radio>
          <a-radio :style="radioStyle" value="not like">不包含</a-radio>
        </a-radio-group>
      </template>
      <a-button type="default" size="small">
        ...
      </a-button>
    </a-popover>
    <div
      ref="optionsContent"
      :class="{
        content: true,
        large: !['varchar', 'text'].includes(column.desc),
      }"
      @scroll="onScrollOptions"
    >
      <div
        v-for="item in filterOptions"
        :key="item.column"
        class="options-item"
        :title="`${item.column}`"
      >
        <a-checkbox
          size="small"
          :checked="selectedValue.includes(item.column)"
          @change="onSelectValue($event, item.column)"
          >{{ `${item.column}` }}</a-checkbox
        >
      </div>
      <div
        v-show="filterOptions.length === 0"
        class="options-item"
        style="margin-top: 20px; text-align: center;"
      >
        暂无数据
      </div>
      <div v-if="isLoading" style="text-align: center;"><a-spin /></div>
    </div>
  </div>
</template>

<script lang="ts">
import { Vue, Component, Prop, Watch } from 'vue-property-decorator'
import { apiGetColumnStat } from '@/api/data-clean'
import { IColumn, IKeyValueStore } from '@/store/modules/dataview'
import { StatisticsAction } from '@/util/data-selection-actions'

@Component
export default class FilterSelectedValue extends Vue {
  @Prop() requestParams: any
  @Prop() column!: IColumn
  @Prop() editData!: any
  @Prop({ default: false }) isEdit!: boolean
  @Prop({ default: '' }) parentTableName!: boolean

  private activeKey: '=' | '<>' = '='
  private filterType: string = 'like'
  private filterTypeMapping: any = {
    '~': 'like',
    'starts with': 'start',
    '=': '=',
    '!~': 'not like',
  }
  private inputValue: string = ''
  private timer: any = null
  private currentPage: number = 1
  private totalPages: number = -1
  private isLoading: boolean = false

  private tabData: any = [
    {
      name: '只保留',
      key: '=',
    },
    {
      name: '排除',
      key: '<>',
    },
  ]
  private filterOptions: any[] = []
  private selectedValue: (string | null)[] = []
  private radioStyle = {
    display: 'block',
    height: '30px',
    lineHeight: '30px',
  }

  mounted() {
    this.getFilterOptions()
  }

  @Watch('editData', { immediate: true, deep: true })
  private onCurrentHistory(newValue: IKeyValueStore) {
    if (!newValue || !this.isEdit) {
      return
    }
    const history = newValue.data
    if (
      history.actionType === StatisticsAction.filterSelected &&
      history.filter[0][0].col === this.column.name
    ) {
      this.activeKey = history.filter[0][0].filterType
      let selectedValue: (string | null)[] = (history.filter[0]
        .filter((item: any) => item.filterType === this.activeKey)
        .map((item: any) => item.values) as []).flat(1)
      if (selectedValue.includes('#NULL')) {
        selectedValue = selectedValue
          .filter((item) => item !== '#NULL')
          .concat(null)
      }
      this.selectedValue = selectedValue
      this.currentPage = 1
      this.getFilterOptions() // 编辑模式下选项是基于上一个表的查询，需要刷新
    }
  }

  private async getFilterOptions(parameters?: any) {
    /* eslint-disable unicorn/prevent-abbreviations */
    this.isLoading = true
    const requestParams = {
      ...(this.requestParams || {}),
    }
    if (this.isEdit) {
      // 编辑模式下，获取的选项是基于上一个记录的表进行查询
      requestParams.table = this.parentTableName // 编辑状态下是基于上一条记录的表名来进行筛选
    }
    const response = await apiGetColumnStat({
      data: {
        ...requestParams,
        ...parameters,
      },
    })
    this.isLoading = false
    if (!response.data.success) {
      this.$message.error(response.data.message)
      return
    }
    const { result } = response.data
    if (result) {
      this.totalPages = result.pageCount.totalPages
      if (this.currentPage > 1) {
        this.filterOptions = [...this.filterOptions, ...result.pageCount.data]
      } else {
        this.filterOptions = result.pageCount.data
      }
    } else {
      this.totalPages = 0
      this.filterOptions = []
    }
  }

  onSelectValue(event: any, value: string) {
    const { checked } = event.target
    if (checked) {
      this.selectedValue = [...this.selectedValue, value]
    } else {
      this.selectedValue = this.selectedValue.filter((item) => item !== value)
    }
    if (this.selectedValue.length > 0) {
      this.emitFilterParams()
    } else {
      this.emitFilterParams('reset')
    }
  }

  emitFilterParams(type?: string) {
    if (type === 'reset') {
      this.$emit('on-filter-params-reset')
    } else {
      this.$emit('on-filter-params-change', {
        data: {
          action: 'FILTER',
          col: this.column.name,
          filter: [
            // 抛出最终用于筛选的选项值
            this.parseFilterParams(),
          ],
          description: `${this.activeKey === '=' ? '只保留' : '排除'}${
            this.selectedValue.length > 1
              ? `${this.selectedValue.length}个值`
              : this.selectedValue[0]
          }`,
          actionType: StatisticsAction.filterSelected, // 筛选模式下action都为FILTER，所以需要增加 actionType 辅助前端区分
        },
      })
    }
  }

  parseFilterParams() {
    const data = []
    if (this.selectedValue.includes(null)) {
      // 包含null值，需要分开成两段
      data.push({
        col: this.column.name,
        filterType: this.activeKey,
        values: ['#NULL'],
      })
    }
    const dataWithoutNull = this.selectedValue.filter((item) => item !== null)
    if (dataWithoutNull.length > 0) {
      data.push({
        col: this.column.name,
        filterType: this.activeKey,
        values: dataWithoutNull,
      })
    }
    return data
  }

  /**
   * 模糊搜索获取选项
   */
  searchOptions() {
    this.currentPage = 1
    const inputValue = this.inputValue.trim()
    this.getFilterOptions({
      searchFilter: [
        [
          {
            col: this.column.name,
            filterType: this.filterType === 'start' ? 'like' : this.filterType,
            values: [this.formatSearchValue(inputValue)],
          },
        ],
      ],
    })
  }

  /**
   * format成查询的格式
   */
  formatSearchValue(value: string): string {
    let formatValue = ''
    switch (this.filterType) {
      case 'start':
        formatValue = `${value}%`
        break
      case 'like':
      case 'not like':
        formatValue = `%${value}%`
        break
      case '=':
        formatValue = value
        break
      default:
        formatValue = value
    }
    return formatValue
  }

  onFilterTypeChange() {
    this.searchOptions()
  }

  toggleTabKey(tab: any) {
    this.activeKey = tab.key
    if (this.selectedValue.length > 0) {
      this.emitFilterParams()
    }
  }

  checkIsLazyLoadOptions(): boolean {
    const { clientHeight, scrollTop, scrollHeight } = this.$refs
      .optionsContent as HTMLDivElement

    if (
      scrollTop + clientHeight + 50 > scrollHeight &&
      this.totalPages >= 0 &&
      this.currentPage < this.totalPages
    ) {
      return true
    }
    return false
  }

  /**
   * 滚动加载
   */
  onScrollOptions() {
    if (this.timer) {
      return
    }
    this.timer = setTimeout(() => {
      this.timer = null
      console.log('onScrollOptions')
      if (this.checkIsLazyLoadOptions()) {
        this.currentPage += 1
        const inputValue = this.inputValue.trim()
        this.getFilterOptions({
          curPage: this.currentPage,
          searchFilter: [
            [
              {
                col: this.column.name,
                filterType: () => {
                  let type = ''
                  switch (this.filterType) {
                    case 'start':
                      type = 'starts with'
                      break
                    case 'like':
                      type = '~'
                      break
                    case 'not like':
                      type = '!~'
                      break
                    default:
                      type = '='
                      break
                  }
                  return type
                },
                values: [this.formatSearchValue(inputValue)],
              },
            ],
          ],
        })
      }
    }, 300)
  }
}
</script>

<style lang="less" scoped>
.filter-selected-value {
  height: 100%;

  .header {
    align-items: center;
    background-color: #fff;
    border-bottom: 1px solid rgba(233, 233, 233, 0.8);
    color: #373b52;
    display: flex;
    font-size: 14px;
    height: 25px;
    justify-content: space-between;
    line-height: 26px;
    padding: 0 12px;
    width: 100%;

    .icon {
      cursor: pointer;
      padding: 8px 12px 8px 0;
    }

    .tabs {
      cursor: pointer;
      display: inline-block;
      height: 25px;
      margin-right: 8px;
      padding: 0 16px;

      &.active {
        border-bottom: 2px solid #5963e5;
        color: #5963e5;
        font-weight: 500;
      }
    }
  }

  .search-box {
    height: 24px;
    margin: 4px 0 8px;
    margin-right: 8px;
    width: 80%;
  }

  .content {
    height: calc(100% - 58px);
    overflow-y: auto;

    &.large {
      height: calc(100% - 28px);
      margin-top: 8px;
    }
  }

  .options-item {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
  }
}
</style>
